package org.robot.scm.platform.server.handler;

import static org.robot.scm.platform.server.LockKey.LOCK_KEY;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.robot.scm.infra.RedisCacheHelper;
import org.robot.scm.platform.server.common.DefaultRunner;
import org.robot.scm.platform.server.common.RunnerLogHelper;
import org.robot.scm.pojos.enums.PlatformEnum;
import org.robot.scm.pojos.platform.server.ExecuteParam;
import org.robot.scm.utils.JsonHelper;
import org.robot.scm.utils.RandomUtil;

/**
 * shell脚本执行
 */
@Slf4j
@NoArgsConstructor
public class ShellExecHandler extends BaseHandler implements HttpHandler {

    @Override
    public String getUri() {
        return "/shellExec";
    }

    @Override
    public void handle(HttpExchange exchange) throws IOException {
        if (!exchange.getRequestMethod().equalsIgnoreCase("POST")) {
            sendFailureResponse(exchange, "请求非法");
            return;
        }

        // 并发校验
        String locker = RedisCacheHelper.get(LOCK_KEY);
        if (StringUtils.isNotBlank(locker)) {
            sendFailureResponse(exchange, "有任务正在执行中");
            return;
        }
        String fileKey = RandomUtil.uuidNoLine();
        String requestBody = new BufferedReader(new InputStreamReader(exchange.getRequestBody(), StandardCharsets.UTF_8)).lines().collect(Collectors.joining("\n"));
        ExecuteParam executeParam = JsonHelper.toObject(requestBody, ExecuteParam.class);
        executeParam.setFileKey(fileKey);
        if (StringUtils.isBlank(executeParam.getScript())) {
            sendFailureResponse(exchange, "请输入执行的脚本");
            return;
        }
        if (checkShell(executeParam.getScript())) {
            sendFailureResponse(exchange, "禁止执行rm或者fork");
            return;
        }

        // 去换行
        StringBuilder command = new StringBuilder();
        String script = executeParam.getScript();
        String[] lines = script.split("\\r?\\n");
        for (String line : lines) {
            ScriptHandler.handleLine(command, line);
        }
        if (!command.toString().trim().endsWith(";")) {
            command.append(";");
        }
        executeParam.setScript(command.toString().trim());
        executeParam.setIsShellExec(Boolean.TRUE);

        RunnerLogHelper.appendStartLog(executeParam.getFileKey(), "shell exec start");
        executeParam.setFileLine(script.split("\\r?\\n").length);
        RedisCacheHelper.put(LOCK_KEY, JsonHelper.toJSONString(executeParam));

        // 处理清理任务
        CompletableFuture.runAsync(() -> new DefaultRunner().start(config(PlatformEnum.SQL), executeParam));
        sendSuccessResponse(exchange, "执行成功", fileKey);
    }

    private boolean checkShell(String script) {
        //rm 和 fork炸弹检测
        return StringUtils.contains(script, "rm ") || StringUtils.contains(script, ":(){ :|:& };:");
    }

}
